#pragma once

#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpConnection.h>
#include <muduo/net/Buffer.h>
#include <muduo/base/CountDownLatch.h>
#include <muduo/net/EventLoopThread.h>
#include <muduo/net/TcpClient.h>
#include "detail.hpp"
#include "fields.hpp"
#include "abstract.hpp"
#include "message.hpp"
#include <mutex>
#include <unordered_map>

//抽象类-调用Muduo高性能库接口实现

namespace bitrpc{

//派生类MuduoBuffer继承基类BaseBuffer，调用muduo::net::Buffer对象相关库实现抽象类接口
    class MuduoBuffer : public BaseBuffer{
        public:
            using prt = std::shared_ptr<MuduoBuffer>;

            MuduoBuffer(muduo::net::Buffer *buf):_buf(buf){}

            //问题:muoduo网络库，调用接口从缓冲区取出一个4字节整形，会进行自动网络字节序的转换
            //在信息进行发送，需要进行手动网络字节序的转换
            virtual size_t readableSize() override{
                return _buf->readableBytes();
            }
            virtual int32_t peekInt32() override{
                //muoduo库是一个网络库，从缓冲区取出一个4字节整形，会进行网络字节序的转换
                return _buf->retrieveInt32();
            }
            virtual void retrieveInt32() override{
                return _buf->readInt32();
            }
            virtual std::string retrieveAsString(size_t len) override{
                return _buf->retrieveAsString(len);
            }
        private:
            muduo::net::Buffer *_buf;
    };

    class BufferFactort{
        public:
            template<typename ...Args>
            static BaseBuffer::ptr create(Args&& ...args){
                return std::make_shared<MuduoBuffer>(std::forward<args>...); 
            }
    };


//派生类LVProtocol协议类继承基类BaseProtocol，调用muduo::net::Buffer对象相关库实现抽象类接口
//格式问题:
        //|--len--|--VALUE--|
        //|--len--|--mtype--|--idlen--|--id--|--body--|

    class LVProtocol : public BaseProtocol{
        public:
        using ptr = std::shared_ptr<LVProtocol>;

        //canProcessed：判断缓冲区中数据是否达到一条完整消息的标准
        virtual boool canProcessed(const BaseBuffer::Ptr &buf) override{
            
            //检查：缓冲区中是否有足够的数据读取消息的长度字段
            if(buf->readableSize()  < lenFieldsLength){
                return false;
            }
    
            int32_t total_len = buf->peekInt32();   //获取该信息字段的总长度
            
            //检查:缓冲区中是否满足完整的消息内容
            if(buf->readableSize() < (total_len + lenFieldsLength)){
                return false;
            }
        }

        //onMessage：
        //默认：缓冲区中的数据足够一条完整的消息(你得到了一条消息)
        //|--len--|--mtype--|--idlen--|--id--|--body--|
        virtual bool onMessage(const BaseBuffer::Ptr &buf, BaseMessage::ptr &msg) override{
            
            //readInt32：读取一个32位整数并移动读指针
            int32_t total_len = buf->readInt32();                                           //读取总长度->idlen字段
            MType mtype = (Mtype)buf->readInt32();                                          //读取数据类型
            int32_t idlen = buf->readInt32();                                               //读取id长度
            int32_t body_len = total_len - idlen - idlenFieldsLength - mtypeFieldsLength;   //body内容大小

            std::string id = buf->retrieveAsString(idlen);                                  //获取ID消息
            std::string body = buf->retrieveAsString(body_len);                             //获取Body内容                    

            msg = BaseMessageFactory::create(mtype);    //根据消息字段中"mtype"创建rpc、topic、service其中请求、响应

            if(msg.get() == nullptr){                   //get() 是智能指针 std::shared_ptr 的成员函数           
                ELOG("信息类型错误，构造消息对象失败");
                return false;
            }

            bool ret = msg->unserialize(body);          //获取消息，进行反序列化读取

            if(ret == false){
                ELOG("消息正文反序列化失败!");
                return false;
            }

            msg->setId(id);
            msg->setMtype(mtype);
            return true;
        } 

        //|--len--|--mtype--|--idlen--|--id--|--body--|
        //serialize：将反序列化数据进行处理完，进行处理添加到结果当中
        virtual std::string serialize(const BaseMessage::ptr &msg) override{  

        std::string body = msg->serialize();            //序列换结果
        std:string id = msg->rid();                     //获取该条消息ID
        
        //将字段转化为网络字节序
        //问题：通过BaseBuffer对象获取消息，会自动转为主机字节序
        //填充到result结果返回，需要手动设置下为网络字节序
        auto mtype =  htonl((int32_t)msg->mtype());
        int32_t idlen = htonl(id.size());
        int32_t h_total_len = mtypeFieldsLength + idlenFieldsLength + id.size() + body.size();
        int32_t n_total_len = htonl(h_total_len);
        
        //填充：将序列化和转化为网络字节序的消息添加到result对象返回
        std::string result;
        result.reserve(h_total_len);
        result.append((char*)&n_total_len, lenFieldsLength);
        result.append((char*)&mtype, mtypeFieldsLength);
        result.append((char*)&idlen, idlenFieldsLength);
        result.append(id);
        result.append(body);
        return result;
    }
    private:
        //使用变量代替特定字段
        const size_t lenFieldsLength = 4;
        const size_t mtypeFieldsLength = 4;
        const size_t idlenFieldsLength = 4;
    };

    class ProtocolFactory{
        public:
            template<typename ...Args>
            static BaseProtocol::ptr create(Args&& ...args){
                return std::make_shared<LVProtocol>(std::forward<Args>(args)...);
            }
    };

//MuduoConnection派生类继承BaseConnection基类，主要通过Muduo高性能网络库"TcpConnectionPtr"完成底层网络通信
    class MuduoConnection : public BaseConnection{
        public:
            using ptr = std::shared_ptr<MuduoConnection>;

            MuduoConnection(const muduo::net::TcpConnectionPtr &conn,
                            const BaseProtocol::ptr &protocol):
                            _protocol(protocol),_conn(conn){};

        virtual void send(const BaseMessage::ptr &msg) override{
            std::string body = _protocol->serialize(msg);      //消息需要通过"BaseProtocol"序列化接口生成result对象返回
            _conn->send(body);                                 //通过Muduo库完成消息的转发和接收
        }

        virtual void shutdown() override{
            _conn->shutdown();                                 //通过Muduo库完成连接关闭
        }
        virtual bool connected() override{
            _conn->connected();                                //通过Muduo库检查连接
        }

        private:
            BaseProtocol::ptr _protocol;                       //负责消息格式处理
            muduo::net::TcpConnectionPtr _conn;               //muduo::net::TcpConnectionPtr负责实际底层网络通信
    } 

    class ConnectionFactory{
        public:
            template<typename ...Args>
            static BaseConnection::ptr create(Args&& ...args){
                return std::make_shared<MuduoConnection>(std::forward<Args>(args)...);
            }
    };

/////////////////////////////////////////////////////////////////////////////////////////////

//MuduoServer继承BaseServer基类， 其中基类封装着不同回调函数处理
//观察者模式实现，允许用户代码在连接建立或断开时执行自定义操作
    class MuduoServer : public BaseServer{
        public:
            using ptr = std::shared_ptr<MuduoServer>;

            MuduoServer(int port):
            _server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port),
                "MuduoServer", muduo::net::TcpServer::kReusePort),
                _protocol(ProtocolFactory::create()){}

            virtual void start(){
                _server.setConnectionCallback(std::bind(&MuduoServer::onConnection, this, std::placeholders::_1));
                _server.setMessageCallback(std::bind(&MuduoServer::onMessage, this, 
                std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

                _server.start();                                                            //先开始监听
                _baseloop.loop();                                                           //开始死循环事件监控
            }

        private:
            void onConnection(const muduo::net::TcpConnectionPtr &conn){
                if(conn->connected()){
                    std::cout << "连接建立!\n";
                    auto muduo_conn = ConnectionFactory::create(conn, _protocol);{
                        std::unique_lock<std::mutex> lock(_mutex);
                        _conns.innsert(std::make_shared(conn, muduo_conn));
                    }
                    if(_cb_connection) _cb_connection(muduo_conn);  //调用"连接回调函数" - 内部设置进行处理
                }
                else{
                    std::cout << "连接断开！\n";
                    BaseConnection::ptr muduo_conn;    
                    {
                        std::unique_lock<std::mutex> lock(_mutex);
                        
                        auto it = _conns.find(conn);                //查找断开服务
                        if(it == _conns.end()){                 
                            return;
                        }  
                        muduo_conn =  it->second;                 //找到需要断开的连接
                    }
                    if(_cb_close) _cb_close(muduo_conn);         //调用"断开回调函数" - 内部设置进行处理
                }
            }

            void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp){
                DLOG("连接有数据到来，开始处理!");
                auto base_buf = BufferFactort::create(buf);
                while(1)
                {
                    if(_protocol->canProcessed(base_buf) == false){
                        //数据不足
                        if(base_buf->readableSize() > maxDateSize){
                            conn->shutdown();
                            ELOG("缓冲区中数据过大!");
                            return ;
                        }
                        DLOG("数据量不足!");
                        break;
                    }
                    DLOG("缓冲区中数据可处理!");
                    BaseMessage::ptr msg;
                    bool ret = _protocol->onMessage(base_buf, msg);     //处理下获得的消息
                    if(ret == false){
                        conn->shutdown();
                        ELOG("缓冲区中数据错误!");
                        return;
                    }
                    
                    DLOG("消息反序列成功!");

                    BaseConnection::base_conn;{
                        std::unique_lock<std::mutex> lock(_mutex);
                        auto it = conns.find(conn);
                        if(it == conns.end())
                        {
                            conn->shutdown();                            //关闭连接
                            return;
                        }
                        base_conn = it->conns->second;
                    }

                    DLOG("调用回调函数进行消息处理!");
                    if(_cb_message) _cb_message(base_conn, msg);        //完成上述消息的检查和转换 - 调用回调函数
                }
            }
        private:
            const size_t maxDateSize = (1 << 16);                                           //使用位运算获取最大数值
            std::mutex _mutex;                                                              //互斥锁
            BaseProtocol::ptr _protocol;                                                    //数据格式处理
            muduo::net::EventLoop _baseloop;                                                //Muduo库事件循环
            muduo::net::TcpServer _server;                                                  //Muduo库TcpServer服务
            std::unordered_map<muduo::net::TcpConnectionPtr, BaseConnection::ptr> _conns;   //[TpcConnectionPrt，BaseConnection::ptr]

            //问题:将"[uduo::net::TcpConnectionPtr, BaseConnection::ptr]"进行捆绑
            //作为一个服务端，底层的网络通信交给了Muduo高性能网络库达成通信操作，提供了必要的两个接口，但是内部的两个接口底层采用了回调函数里面自定义操作处理
            // 其中涉及内部自定义操作处理，采用了BaseConnection作为接口，内部配置了MuduoConnect实现主要功能，达到了可扩展、可维护的网络应用框架
            // 上层只需要域BaseConnection接口交互即可。
    }

    class ServerFactory{
        public:
        template<typename ...Args>
        static BaseServer::ptr create(Args&& ...args){
            return std::make_shared<MuduoServer>(std::forward<Args>(args)...);
        }
    };

    //Mudou客户端
    class MuduoClient : public BaseClient{
        public: 
            using ptr = std::shared_ptr<MuduoClient>;

        private:
            void onConnection(const muduo::net::TcpConnectionPtr &conn){
                if(conn->connected){
                    std::cout << "连接建立!\n";
                    _downlatch.CountDownLatch();                        //计数--， 为0唤醒阻塞
                    _conn = ConnectionFactory::create(conn, _protocol);
                }
                else{
                    std::cout << "连接断开！\n";
                    _conn.reset();                                      //重新连接
                }
            }
            void onMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buf, muduo::Timestamp){
                DLOG("连接有数据到来，开始处理!");
                auto base_buf = BufferFactort::create(buf);
                while(1){
                    if(_protocol->canProcessed(base_buf) == false){    
                        if(base_buf->readableSize() > maxDateSize){
                            conn->shutdown();
                            ELOG("缓冲区中数据过大!");
                            return ;
                        }
                        DLOG("数据量不足!");
                        break;
                    }
                    DLOG("缓冲区中数据可处理!");
                    BaseMessage::ptr msg;
                    bool ret = _protocol->onMessage(base_buf, msg);
                    if(ret == false){
                        conn->shutdown();
                        ELOG("缓冲区中数据错误!");
                        return;
                    }
                    DLOG("缓冲区中数据解析完毕，调用回调函数进行处理!");
                    if(_cb_message) _cb_message(_conn,msg);             //同服务端操作类似 - 交给自定义回调函数处理
                }
            }
            
        private:
            const size_t maxDateSize = (1 << 16);
            BaseProtocol::ptr _protocol;
            BaseConnection::ptr  _conn;
            muduo::CountDownLatch _downlatch;
            muduo::net::EventLoopThread *_loopthread;   //提供客户端多线程访问
            muduo::net::EventLoop *_baseloop;
            muduo::net::TcpClient _client;
    };

    class ClientFactory{
        public:
            template<typename ...Args>
            static BaseClient::ptr create(Args&& ...){
                return std::make_shared<MuduoClient>(std::forward<Args>(args)...);
            }
    }
};